home *** CD-ROM | disk | FTP | other *** search
- /*
- * hearts_dist - distributor for hearts
- *
- * Keeps track of games in progress and allows new players to select which
- * game to join or start a new game.
- *
- *
- * Commands to hearts player:
- * tn Following info regards table n (n is unique identifier).
- * hn Now playing hand n.
- * rn Now playing round n.
- * pn<name> Player n is <name>.
- *
- * xn Table n has exited (game over).
- * g Get table number to join.
- * cn Connect to dealer on port n.
- *
- * Commands from hearts player:
- * jn Join table n.
- * n Start new game.
- *
- * Commands to dealer:
- * none yet?!?
- *
- * Commands from dealer:
- * hn Now playing hand n.
- * rn Now playing round n.
- * pn<name> Player n is <name>.
- *
- */
- /*
- * MODIFICATION HISTORY
- *
- * S001 rr@sco.com 14 May 93
- * - Use Internet Domain sockets rather than Unix Domain sockets
- * S002 mikep@sco.com 22 June 93
- * - Fix bug in socket call. Need to save the fd in socks[x]
- * Note this don't work yet.
- */
-
- #include "misc.h"
- #include "defs.h"
- #include "local.h"
- #include <string.h>
- #include <malloc.h>
-
- typedef struct table *table_ptr;
-
- struct table {
- table_ptr next_table; /* Points to next table entry */
- int table_id; /* Unique identifier */
- char player_name[4][9]; /* Name of players at table */
- int hand; /* Current dealer hand (1..4) */
- int round; /* Current round (1..13) */
- int port_num; /* Port # assigned */
- int socket; /* File descriptor for dealer */
- int pid; /* Process id for dealer */
- };
-
- typedef struct empty_table *empty_ptr;
-
- struct empty_table {
- empty_ptr next_empty;
- int port_num; /* Available port # */
- };
-
- typedef struct new_comer *new_ptr;
-
- struct new_comer {
- new_ptr next_new_comer;
- int socket; /* File descriptor */
- };
-
- table_ptr first_table;
- empty_ptr first_empty;
- new_ptr first_new_comer;
-
- int main_sock,
- next_port, /* Next port to assign */
- unique_id;
-
- /*
- * clear_table - dealer went away; drop that table.
- */
- clear_table(tbl_ptr)
- table_ptr tbl_ptr;
- {
- table_ptr prev_ptr = NULL;
- table_ptr cur_ptr;
- empty_ptr temp_empty, cur_empty;
- new_ptr cur_new_comer;
- char buf[16];
-
- while (wait(0) != tbl_ptr->pid) /* Wait for process to die */
- ;
- (void) close(tbl_ptr->socket);
- /*
- * Inform new-comers
- */
- (void) sprintf(buf, "x%d", tbl_ptr->table_id);
- for (cur_new_comer = first_new_comer; cur_new_comer;
- cur_new_comer = cur_new_comer->next_new_comer)
- write_socket(cur_new_comer->socket, buf);
- for (cur_ptr = first_table; cur_ptr != tbl_ptr;
- cur_ptr = cur_ptr->next_table)
- prev_ptr = cur_ptr;
- if (prev_ptr)
- prev_ptr->next_table = tbl_ptr->next_table;
- else
- if ((first_table = tbl_ptr->next_table) == NULL &&
- first_new_comer == NULL)
- exit(0); /* No more dealers */
- ;
- if (first_table) {
- temp_empty = (empty_ptr) malloc(sizeof(struct empty_table));
- temp_empty->next_empty = NULL;
- temp_empty->port_num = tbl_ptr->port_num;
- free((char *) tbl_ptr);
- if (first_empty) {
- for (cur_empty = first_empty; cur_empty->next_empty;
- cur_empty = cur_empty->next_empty) ;
- cur_empty->next_empty = temp_empty;
- }
- else
- first_empty = temp_empty;
- }
- }
-
- /*
- * drop_new_comer - New comer exited
- */
- drop_new_comer(dead_new_comer)
- new_ptr dead_new_comer;
- {
- new_ptr cur_new_comer,
- prev_new_comer = NULL;
-
- (void) close(dead_new_comer->socket);
- for (cur_new_comer = first_new_comer; cur_new_comer != dead_new_comer;
- cur_new_comer = cur_new_comer->next_new_comer)
- prev_new_comer = cur_new_comer;
- if (prev_new_comer)
- prev_new_comer->next_new_comer = dead_new_comer->next_new_comer;
- else
- first_new_comer = dead_new_comer->next_new_comer;
- free((char *) dead_new_comer);
- if ((first_table == NULL) && (first_new_comer == NULL))
- exit(0); /* Nobody connected */
- }
-
- /*
- * new_player - New player has connected. Inform of games in progress and
- * request game to be joined.
- */
- new_player()
- {
- int new_socket; /* new file descriptor */
- char buf[64];
- struct sockaddr_in sockad;
- int ssize; /* makes accept happy */
- int i;
- new_ptr cur_new_comer, temp_new_comer;
- table_ptr cur_ptr;
-
- /*
- * add whoever's waiting
- */
- ssize = sizeof (sockad);
- if ((new_socket = accept(main_sock, &sockad, &ssize)) == -1) {
- perror("accept");
- exit(-1);
- }
- /*
- * add to list of new_comers
- */
- temp_new_comer = (new_ptr) malloc(sizeof(struct new_comer));
- temp_new_comer->next_new_comer = NULL;
- temp_new_comer->socket = new_socket;
- if (first_new_comer) {
- for (cur_new_comer = first_new_comer;
- cur_new_comer->next_new_comer;
- cur_new_comer = cur_new_comer->next_new_comer) ;
- cur_new_comer->next_new_comer = temp_new_comer;
- }
- else {
- first_new_comer = temp_new_comer;
- first_new_comer->next_new_comer = NULL;
- }
- /*
- * send info on games in progress
- */
- for (cur_ptr = first_table; cur_ptr; cur_ptr = cur_ptr->next_table) {
- (void) sprintf(buf, "t%d", cur_ptr->table_id);
- write_socket(new_socket, buf);
- (void) sprintf(buf, "h%d", cur_ptr->hand);
- write_socket(new_socket, buf);
- (void) sprintf(buf, "r%d", cur_ptr->round);
- write_socket(new_socket, buf);
- for (i = 0; i < 4; i++) {
- (void) sprintf(buf, "p%d%s", i, cur_ptr->player_name[i]);
- write_socket(new_socket, buf);
- }
- }
- write_socket(new_socket, "g");
- }
-
- tell_new_comers(buf)
- char *buf;
- {
- new_ptr cur_new;
-
- for (cur_new = first_new_comer; cur_new;
- cur_new = cur_new->next_new_comer)
- write_socket(cur_new->socket, buf);
- }
-
- /*
- * join - join an existing table. table_num is unique identifier for table.
- */
- join(table_num, socket)
- int table_num, socket;
- {
- table_ptr cur_ptr;
- char buf[16];
-
- for (cur_ptr = first_table; cur_ptr && cur_ptr->table_id != table_num;
- cur_ptr = cur_ptr->next_table) ;
- if (cur_ptr) {
- (void) sprintf(buf, "c%d", cur_ptr->port_num);
- write_socket(socket, buf);
- }
- else
- write_socket(socket, "g"); /* Table doesn't exist?!? */
- }
-
- /*
- * new_table - start new hearts game.
- */
- new_table(cur_new_comer)
- new_ptr cur_new_comer;
- {
- table_ptr cur_table, new_tbl_ptr;
- empty_ptr tmp_empty;
- int i, socks[2];
- int dealer_port, dealer_socket, retry = 0;
- char buf[16], filename[1024];
-
- new_tbl_ptr = (table_ptr) malloc(sizeof(struct table));
- new_tbl_ptr->next_table = NULL;
- new_tbl_ptr->table_id = ++unique_id;
- for (i = 0; i < 4; i++)
- (void) strcpy(new_tbl_ptr->player_name[i], "<empty>");
- /*
- * Assign a port. Reassign a used port if available.
- */
- do {
- if (first_empty) {
- dealer_port = first_empty->port_num;
- tmp_empty = first_empty;
- first_empty = first_empty->next_empty;
- free((char *) tmp_empty);
- }
- else
- dealer_port = next_port++;
- /*
- * Make sure port is ok before assigning.
- */
- if ((dealer_socket = open_socket(dealer_port)) == 0)
- if (++ retry == 20) {
- fputs("Can't open a dealer port!\n", stderr);
- exit(1);
- }
- }
- while (dealer_socket == 0);
- new_tbl_ptr->port_num = dealer_port;
- /*
- * Open a socket pair to talk to dealer on.
- */
- if (socks[0] = socket(AF_INET, SOCK_STREAM, 0) == -1) { /* S002 */
- perror("socket[0]");
- exit(1);
- }
- if (socks[1] = socket(AF_INET, SOCK_STREAM, 0) == -1) { /* S002 */
- perror("socket[1]");
- exit(1);
- }
- switch (new_tbl_ptr->pid = fork()) {
- case 0:
- (void) setpgrp (0, getpid());
- (void) close(socks[0]);
- if (socks[1] != 3)
- (void) dup2(socks[1], 3); /* Remap to fd 3 */
- if (dealer_socket != 4)
- (void) dup2(dealer_socket, 4); /* Remap to fd 4 */
- sprintf(filename, "%s/%s", HEARTSLIB, HEARTSD);
- execl (filename, "heartsd", 0);
- exit(1);
- case -1:
- perror("fork");
- exit(1);
- }
- (void) close(socks[1]);
- (void) close(dealer_socket);
-
- new_tbl_ptr->socket = socks[0];
- if (first_table) {
- for (cur_table = first_table; cur_table->next_table;
- cur_table = cur_table->next_table)
- ;
- cur_table->next_table = new_tbl_ptr;
- }
- else
- first_table = new_tbl_ptr;
- /*
- * Inform hearts player of port # to connect on.
- */
- (void) sprintf(buf, "c%d", dealer_port);
- write_socket(cur_new_comer->socket, buf);
- }
-
- main(argc, argv)
- char **argv;
- {
- fd_type read_fd;
- table_ptr cur_table;
- new_ptr cur_new_comer;
- char buf[64], tmp_buf[64];
- int ret;
- int table_num;
- char debug = FALSE;
-
- while (*++argv) {
- if (**argv == '-') {
- while (*++*argv) {
- switch (**argv) {
- case 'd':
- debug = TRUE;
- break;
-
- default:
- fprintf (stderr, "usage: hearts_dist [-d]\n");
- exit (1);
- break;
- }
- }
- }
- }
-
- first_table = NULL;
- first_empty = NULL;
- first_new_comer = NULL;
- next_port = DIST_PORT;
- unique_id = 0;
-
- if ((main_sock = open_socket(PORT)) == 0) {
- fputs("Distributor port in use!\n", stderr);
- exit(1);
- }
- if (!debug) {
- /*
- * Fork off and die. Thus hearts invoker wait() returns.
- * This signals ready to connect.
- */
- if (fork())
- exit (0);
- }
-
- for (;;) {
- fd_init(main_sock, &read_fd);
- /*
- * Build mask for dealers
- */
- for (cur_table = first_table; cur_table;
- cur_table = cur_table->next_table)
- fd_set(cur_table->socket, &read_fd);
- /*
- * Build mask for new_comers
- */
- for (cur_new_comer = first_new_comer; cur_new_comer;
- cur_new_comer = cur_new_comer->next_new_comer)
- fd_set(cur_new_comer->socket, &read_fd);
-
- /*
- * Wait for something to happen
- */
- if (select(WIDTH, &read_fd, (fd_type *) 0, (fd_type *) 0,
- (struct timeval *) 0)) {
- if (fd_isset(main_sock, read_fd))
- new_player();
- for (cur_table = first_table; cur_table;
- cur_table = cur_table->next_table)
- if (fd_isset(cur_table->socket, read_fd)) {
- /*
- * Message from dealer
- */
- ret = read_socket(cur_table->socket, buf);
- if (!ret) {
- clear_table(cur_table);
- break;
- } else {
- switch (buf[0]) {
- case 'h' :
- (void) sscanf(buf + 1, "%d", &cur_table->hand);
- break;
- case 'r' :
- (void) sscanf(buf + 1, "%d", &cur_table->round);
- break;
- case 'p' :
- (void) strcpy(cur_table->player_name[buf[1] - '0'], buf + 2);
- }
- (void) sprintf(tmp_buf, "t%d", cur_table->table_id);
- tell_new_comers(tmp_buf);
- tell_new_comers(buf);
- }
- }
- for (cur_new_comer = first_new_comer; cur_new_comer;
- cur_new_comer = cur_new_comer->next_new_comer)
- if (fd_isset(cur_new_comer->socket, read_fd)) {
- /*
- * Message from newcomer
- */
- ret = read_socket(cur_new_comer->socket, buf);
- if (ret)
- switch (buf[0]) {
- case 'j' :
- (void) sscanf(buf + 1, "%d", &table_num);
- join(table_num, cur_new_comer->socket);
- break;
-
- case 'n' :
- new_table(cur_new_comer);
- }
- else {
- drop_new_comer(cur_new_comer);
- break;
- }
- }
- }
- }
- }
-
-